<script setup>
import service from '@/utils/request.utils';
import { ElMessage } from 'element-plus';
import { computed, onBeforeMount, ref } from 'vue';
import { Download } from '@element-plus/icons-vue'
import { getCookie } from '@/utils/cookie.utils';
import 'highlight.js/styles/monokai.css';
import Markdown from 'vue3-markdown-it';
import { useStore } from 'vuex'
import * as echarts from 'echarts'

const store = useStore()

// const aiItem = {
//     role: "AI助手",
//     message: "```sql\n SELECT `nickname`,`age` FROM `User`",
//     result: [{ nickname: "小王", age: 18 }, { nickname: "小刘", age: 22 }, { nickname: "小华", age: 24 }],
//     fields: ["nickname", "age"],
//     type: "chart",
//     value: [["小王", 18], ["小刘", 22], ["小华", 24]],
//     index: "echarts0"
// }

const history = ref([
    {
        role: "AI助手",
        message: "请问我有什么可以帮到你的吗？"
    },
    // {
    //     role: "人类",
    //     message: "请问 1 + 1 等于多少？"
    // },
    // aiItem

])
const question = ref(null)
const btn = ref(false)

const hubList = ref([])
const databaseList = ref([])

const hubSelectedOrigin = ref(null)
const chartOptions = ref([])
const activeName = ref("table")
let chartCount = -1

const fileList = ref([])

const referenceCount = ref(3)
const referencePadding = ref(1)
const useReference = ref(false)
const contextCount = ref(3)

const askType = ref(null)

const hubSelected = computed({
    get() {
        return hubSelectedOrigin.value
    },
    // 需要监听数据变化
    async set(newValue) {
        hubSelectedOrigin.value = newValue
        queryDatabase()
        queryAllHubs()
    }
})

const databaseSelectedOrigin = ref(null)
const databaseSelected = computed({
    get() {
        return databaseSelectedOrigin.value
    },
    set(newValue) {
        databaseSelectedOrigin.value = newValue
    }
})

async function queryAllHubs() {
    if (hubSelectedOrigin == null) {
        ElMessage.warning("请选择一个知识库")
        return
    } else {
        let res = await service.post("/file/querys", { hubId: hubSelectedOrigin.value["hub_id"] })
        console.log(res)

        if (res.status != 200) {
            ElMessage({
                message: '操作失败: ' + res.status,
                type: 'error'
            })
        }

        if (res.data.code != '0') {
            console.log(res.data)
            ElMessage({
                message: RESPONSE_MESSAGE[res.data.code],
                type: "warning"
            })
        } else {
            let data = res.data.data

            fileList.value = data
            return
        }

    }
}

async function queryDatabase() {
    if (hubSelectedOrigin == null) {
        ElMessage.warning("请先选择一个知识库")
        return
    } else {
        let res = await service.post("/database/querys", { hubId: hubSelectedOrigin.value["hub_id"] })
        console.log(res)

        if (res.status != 200) {
            ElMessage({
                message: '操作失败: ' + res.status,
                type: 'error'
            })
        }

        if (res.data.code != '0') {
            console.log(res.data)
            ElMessage({
                message: res.data.msg,
                type: "warning"
            })
        } else {
            let data = res.data.data
            databaseList.value = data
            if (data.length == 0) {
                ElMessage.info("该知识库没有数据库源！")
            }
            return
        }

    }
}

function initChartOptions(columns, data, title = "", type = "bar") {
    let Xs = []
    let Ys = []
    for (let i in data) {
        Xs.push(data[i][0])
        Ys.push(data[i][1])
    }

    let option = {
        title: {
            text: title
        },
        tooltip: {},
        // legend: {
        //     data: columns[1],
        // },
        xAxis: {
            data: Xs
        },
        yAxis: {},
        series: [{
            name: columns[1],
            type: type,
            data: Ys
        }]
    };

    chartOptions.value.push(option)
}

function tableSwitch(id) {
    console.log("id", id)
    let element = document.getElementById(id)
    console.log(element)
    let chart = echarts.init(element)
    let index = id.split("charts")[1]
    console.log(index, chartOptions.value[index])
    chart.setOption(chartOptions.value[index])
}

// initChartOptions(aiItem.fields, aiItem.value);

async function askDB() {

    btn.value = true
    if (databaseSelectedOrigin.value == null) {
        ElMessage.warning("未选择一个数据库源")
        btn.value = false
        return
    }


    if (question.value == null || question.value.lenght == 0) {
        ElMessage.warning("聊天输入不能为空")
        btn.value = false
        return
    }

    const message = question.value
    question.value = null


    try {
        let llm = store.state.model
        let temperature = store.state.temperature
        let data = {
            "databaseId": databaseSelectedOrigin.value.id, "question": message, "llm": llm, "temperature": temperature
        }
        let res = service.post("/chat/database", data)
        history.value.push({ "role": "人类", "message": message })
        res = await res;
        console.log(res)
        if (res.status != 200) {
            ElMessage({
                message: '操作失败: ' + res.status,
                type: 'error'
            })
        }

        if (res.data.code != '0') {
            console.log(res.data)
            ElMessage({
                message: res.data.msg,
                type: "warning"
            })
        } else {
            let data = res.data.data
            let sql = data["sql"]
            let result = data["data"]
            let fields = []
            let values = []

            console.log("result", result)
            if (result != null && result.length > 0) {
                let one = result[0]
                for (let i in one) {
                    console.log(i)
                    fields.push(i)
                }
                for (let i in result) {
                    let tmp = []
                    let one = result[i]
                    for (let k in one) {
                        tmp.push(one[k])
                    }
                    values.push(tmp)
                }
            }

            let type = "table"
            if (fields.length == 2) {
                if (!isNaN(values[0][1])) {
                    type = "chart"
                    chartCount++
                    initChartOptions(fields, values)
                }

            }

            let k = sql.indexOf("SQLResult")
            if (k != -1) {
                sql = sql.slice(0, k)
            }
            if (sql.indexOf("```") != 0) {
                sql = '```sql\n' + sql + "\n```"
            }
            let aiResponse = { "role": "AI助手", "message": sql, "result": result, "fields": fields, "type": type, "index": "echarts" + chartCount }
            console.log(aiResponse)
            history.value.push(aiResponse)
            btn.value = false
            return
        }

        history.value.pop()
        btn.value = false
        return
    } catch (e) {
        console.log(e)
        ElMessage.error(e)
        history.value.pop()
        btn.value = false
        return
    }
}

async function askDoc() {

    if (fileList.value.lenght == 0) {
        ElMessage.warning("未选择一个知识库或者知识库没有文件")
        return
    }


    btn.value = true
    if (question.value == null || question.value.lenght == 0) {
        ElMessage.warning("聊天输入不能为空")
        return
    }

    const message = question.value
    question.value = null


    try {
        let data = null
        let llm = store.state.model
        let temperature = store.state.temperature

        // 处理历史信息
        let count = contextCount.value;
        let context = []

        if (count != 0) {
            let index = 0;
            let historyLength = history.value.lenght;
            if (2 * count < historyLength) {
                index = historyLength - 2 * count;
            }
            for (; index < historyLength; index++) {
                if (history[i].type) {
                    // 说明是数据库问答的历史数据 
                    if (history[i].result && history[i].result.length > 0) {
                        context.push({ "role": "AI助手", "message": "SQL: " + history[i].message + "\n查询结果：" + JSON.stringify(history[i].result) + "\n" })
                    } else {
                        context.push({ "role": "AI助手", "message": "SQL: " + history[i].message + "\n查询结果为空" })
                    }
                } else {
                    context.push(history[i])
                }

            }

        }

        if (hubSelectedOrigin.value == null) {
            data = {
                "history": context, "question": message, "llm": llm, "temperature": temperature
            }
        } else {
            data = {
                "history": context, "question": message,
                "useReference": useReference.value, "referenceCount": referenceCount.value,
                "referencePadding": referencePadding.value,
                "hubId": hubSelectedOrigin.value["hub_id"],
                "llm": llm, "temperature": temperature
            }
        }

        let res = service.post("/chat/knowledge", data)
        history.value.push({ "role": "人类", "message": message })
        res = await res;
        console.log(res)

        if (res.status != 200) {
            ElMessage({
                message: '操作失败: ' + res.status,
                type: 'error'
            })
        }

        if (res.data.code != '0') {
            console.log(res.data)
            ElMessage({
                message: RESPONSE_MESSAGE[res.data.code],
                type: "warning"
            })
        } else {
            let data = res.data.data
            let chatOutput = data['chatOutput']
            let references = data["references"]
            if (!references) {
                history.value.push({ "role": "AI助手", "message": chatOutput })
            }
            else {
                let hub_name = data["hub_name"]
                let referenceItems = []
                for (let i in references) {
                    let tmp = references[i]
                    referenceItems.push({
                        "file_id": tmp[0],
                        "file_name": tmp[2] + "(" + hub_name + ")",
                        "content": tmp[1],
                        "page_number": tmp[3],
                        "distance": tmp[4]
                    })
                }
                referenceItems.sort((a, b) => { b.distance - a.distance })
                if (chatOutput.indexOf("AI助手：") == 0 || chatOutput.indexOf("AI助手:") == 0) {
                    chatOutput = chatOutput.slice(5)
                }
                history.value.push({ "role": "AI助手", "message": chatOutput, "reference": referenceItems })
            }
            btn.value = false
            return
        }

        history.value.pop()
        btn.value = false
        return
    } catch (e) {
        console.log(e)
        ElMessage.error(e)
        history.value.pop()
        btn.value = false
        return
    }
}

async function send() {
    if (askType.value == null) {
        ElMessage.warning("请选择问答方式")
    }
    else if (askType.value == '2') {
        askDB()
    }
    else {
        askDoc()
    }
}

function download(file) {
    console.log(file)
    const downloadUrl = import.meta.env.VITE_API_ADDR + "/" + "download/document?hubId=" + file["hub_id"] + "&fileId=" + file["id"] + "&token=" + getCookie("token")
    window.open(downloadUrl, '_blank')
}


onBeforeMount(async () => {
    let res = await service.post("/hub/queryAll")
    console.log(res)

    if (res.status != 200) {
        ElMessage({
            message: '操作失败: ' + res.status,
            type: 'error'
        })
    }

    if (res.data.code != '0') {
        console.log(res.data)
        ElMessage({
            message: RESPONSE_MESSAGE[res.data.code],
            type: "warning"
        })
    } else {
        let data = res.data.data
        for (let i in data) {
            data[i]["hub_group"] = data[i]["hub_name"] + " (群组：" + data[i]["group_name"] + ")"
        }
        hubList.value = data
        return
    }

    history.value.pop()
    btn.value = false
    return
})

</script>

<template>
    <div id="outer">
        <h2 style="position: absolute;top: -15px">Chat All</h2>
        <div id="chat-framework">
            <div id="chat-content">
                <div class="chat-message-item" v-for="item in  history ">
                    <div class="chat-human-message" v-if="item.role == '人类'">
                        <div class="human-content content-padding">
                            {{ item.message }}
                        </div>
                        <div class="user">
                            你
                        </div>
                    </div>
                    <div class="chat-ai-message" v-else>
                        <div class="user">
                            AI
                        </div>
                        <div class="ai-content content-padding">
                            <Markdown class="markdown-style" :source="item.message"></Markdown>
                            <div class="ai-reference" v-if="item.type && item.result && item.result.length > 0">
                                <el-tabs v-model="activeName" style="width: 100%;">
                                    <el-tab-pane label="表格" name="table">
                                        <el-table :data="item.result" stripe style="width: 100%">
                                            <el-table-column v-for=" field  in  item.fields " :prop="field"
                                                :label="field" />
                                        </el-table>
                                    </el-tab-pane>
                                    <el-tab-pane name="picture" v-if="item.type != 'table'">
                                        <template #label>
                                            <div @click=" tableSwitch(item.index)">统计图</div>
                                        </template>
                                        <div :id="item.index" style="width: 200px;height:200px;">
                                        </div>
                                    </el-tab-pane>
                                </el-tabs>
                            </div>
                            <div class="ai-reference" v-if="!item.type && item.reference">
                                引用：<div class="ai-reference-item" v-for=" reference  in  item.reference ">
                                    <el-tooltip effect="dark" popper-class="tooltip-width">
                                        <a>{{ reference.distance }}</a>
                                        <template #content>
                                            <div>
                                                <p style="font-size: smaller; font-weight: 800;white-space: pre-wrap;">
                                                    {{ "《" + reference.file_name + "》》 页码：" + reference.page_number }}
                                                </p>
                                                <p style="white-space: pre-wrap;">
                                                    {{ reference.content }}
                                                </p>
                                            </div>
                                        </template>
                                    </el-tooltip>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            <div id="chat-input">
                <el-input placeholder="请输入聊天信息" v-model="question" @keyup.enter.native="send"
                    id="chat-input-box"></el-input>
                <el-button id="chat-input-btn" @click="send" :disabled="btn" type="success">发送</el-button>
            </div>
        </div>
        <div id="hub-panel">

            <div id="panel">
                <div id="panel">
                    <el-tooltip effect="dark" content="选择进行原生问答、文档问答还是数据库问答!">
                        <el-form-item label="选择问答方式">
                            <el-select v-model="askType" placeholder="选择问答方式" size="large" style="width: 240px">
                                <el-option label="原生问答" value="0" />
                                <el-option label="文档问答" value="1" />
                                <el-option label="数据库问答" value="2" />
                            </el-select>
                        </el-form-item>
                    </el-tooltip>
                    <el-form-item label="请选择知识库">
                        <el-select v-model="hubSelected" placeholder="选择一个知识库" size="large" style="width: 240px">
                            <el-option v-for=" hub  in  hubList " :key="hub.hub_id" :label="hub.hub_group" :value="hub" />
                        </el-select>
                    </el-form-item>
                    <el-tooltip effect="dark" content="是否将引用加入到聊天的上下文中，由于引用内容比较长，会占用大量Token，在长对话中不建议开启！">
                        <el-form-item label="引用入上下文">
                            <el-switch v-model="useReference" size="middle" style="--el-switch-on-color: #13ce66;" />
                        </el-form-item>
                    </el-tooltip>
                    <el-tooltip effect=" dark" content="需要检索出的引用数量，注意如果引用文本是同一个文档的顺序切分，在目标引用扩展不为0的情况下，会进行拼接！">
                        <el-form-item label="检索引用数目">
                            <el-input-number v-model="referenceCount" :max="10" :min="1" type="number" />
                        </el-form-item>
                    </el-tooltip>
                    <el-tooltip effect="dark" content="检索到目标引用后需要对目标引用进行上下文扩展，注意扩展是对称的，值为一个方向上扩展的最大数目!">
                        <el-form-item label="目标引用扩展">
                            <el-input-number v-model="referencePadding" :max="10" min="0" type="number" />
                        </el-form-item>
                    </el-tooltip>
                    <el-tooltip effect="dark" content="将至多多少对对话加入到历史上下文中">
                        <el-form-item label="上下文对话数">
                            <el-input-number v-model="contextCount" :max="10" min="0" type="number" />
                        </el-form-item>
                    </el-tooltip>
                </div>
            </div>
            <div class="base-list" :class="{ 'database-list': askType == '2' && databaseList.length > 0 }">
                <el-table v-if="askType == '1' && fileList.length > 0" :data="fileList"
                    style="width: 100%;text-align: center;" :header-cell-style="{ textAlign: 'center' }"
                    :cell-style="{ textAlign: 'center' }" border>
                    <el-table-column prop="file_name" label="文件名" width="180" />
                    <el-table-column prop="create_at" label="上传时间" width="180" />
                    <el-table-column prop="download" label="下载">
                        <template #default="scope">
                            <el-button type="info" class="download" @click="download(scope.row)" :icon="Download">
                                下载
                            </el-button>
                        </template>
                    </el-table-column>
                </el-table>
                <el-form-item v-if="askType == '2' && databaseList.length > 0" label="请选择数据库源">
                    <el-select v-model="databaseSelected" placeholder="选择一个数据库源" size="large" style="width: 240px">
                        <el-option v-for="  database   in   databaseList  " :key="database.id" :label="database.database"
                            :value="database" />
                    </el-select>
                </el-form-item>
            </div>
        </div>
    </div>
</template>


<style scoped>
#outer {
    position: relative;
    margin: auto;
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: space-around;
}

#chat-framework {
    width: 60%;
    height: 90%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: space-around;
}

#chat-content {
    height: 90%;
    width: 100%;
    overflow: auto;
    border: 2px rgb(120, 120, 120) dashed;
    border-radius: 5px;
    background-color: rgb(245, 245, 245);

}

.chat-message-item {
    width: 100%;
    position: relative;
    margin-top: 5px;
    margin-bottom: 5px;
}

.chat-human-message {
    display: flex;
    flex-direction: row;
    justify-content: flex-end;
    width: 100%;
}

.chat-ai-message {
    display: flex;
    flex-direction: row;
    justify-content: flex-start;
    width: 100%;
}

.content-padding {
    padding-left: 10px;
    padding-right: 10px;
    padding-top: 7px;
    padding-bottom: 7px;
}

.human-content {
    max-width: 70%;
    background-color: goldenrod;
    border-radius: 5px;
}

.ai-content {
    max-width: 50%;
    background-color: white;
    display: flex;
    flex-direction: column;
    border-radius: 5px;
}

.ai-reference {
    margin-top: 10px;
    padding-top: 5px;
    border-top: 2px rgb(200, 200, 200) solid;
    font-size: 10px;
    font-weight: 800;
    display: flex;
    flex-direction: row;
    white-space: normal;
}

.ai-reference-item {
    width: fit-content;
    height: fit-content;
    padding-left: 3em;
    padding-right: 5em;
    cursor: pointer;
}

.user {
    margin-left: 0.3em;
    margin-right: 0.3em;
    margin-top: 5px;
    font-size: 1.2em;
    width: fit-content;
    font-weight: 700;
}


#chat-input {
    height: 10%;
    width: 100%;
    display: flex;
    flex-direction: row;
    justify-content: center;
    align-items: center;
}

#hub-panel {
    width: 38%;
    height: 90%;
    border: 2px rgb(200, 200, 200) solid;
    border-radius: 1em;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
}

#panel {
    height: 50%;
    width: 90%;
    padding-top: 5%;
    padding-left: 5%;
    padding-right: 10%;
}

.database-list {
    padding-left: 2em;
}

.base-list {
    height: 50%;
    width: 100%;
    overflow: auto;
}
</style>

<style lang="less">
.tooltip-width {
    max-width: 800px;
}

.markdown-style {
    margin-top: -15px;
    margin-bottom: -15px;
}
</style>

